Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(123)

Side by Side Diff: pkg/analyzer_cli/lib/src/driver.dart

Issue 2963323002: Add analytics to analyzer-cli and analysis server. (Closed)
Patch Set: update from review comments Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « pkg/analyzer_cli/lib/src/build_mode.dart ('k') | pkg/analyzer_cli/lib/src/options.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 import 'dart:async'; 5 import 'dart:async';
6 import 'dart:io' as io; 6 import 'dart:io' as io;
7 7
8 import 'package:analyzer/error/error.dart'; 8 import 'package:analyzer/error/error.dart';
9 import 'package:analyzer/file_system/file_system.dart' as file_system; 9 import 'package:analyzer/file_system/file_system.dart' as file_system;
10 import 'package:analyzer/file_system/file_system.dart'; 10 import 'package:analyzer/file_system/file_system.dart';
(...skipping 24 matching lines...) Expand all
35 import 'package:analyzer_cli/src/batch_mode.dart'; 35 import 'package:analyzer_cli/src/batch_mode.dart';
36 import 'package:analyzer_cli/src/build_mode.dart'; 36 import 'package:analyzer_cli/src/build_mode.dart';
37 import 'package:analyzer_cli/src/error_formatter.dart'; 37 import 'package:analyzer_cli/src/error_formatter.dart';
38 import 'package:analyzer_cli/src/error_severity.dart'; 38 import 'package:analyzer_cli/src/error_severity.dart';
39 import 'package:analyzer_cli/src/options.dart'; 39 import 'package:analyzer_cli/src/options.dart';
40 import 'package:analyzer_cli/src/perf_report.dart'; 40 import 'package:analyzer_cli/src/perf_report.dart';
41 import 'package:analyzer_cli/starter.dart' show CommandLineStarter; 41 import 'package:analyzer_cli/starter.dart' show CommandLineStarter;
42 import 'package:front_end/src/base/performace_logger.dart'; 42 import 'package:front_end/src/base/performace_logger.dart';
43 import 'package:front_end/src/incremental/byte_store.dart'; 43 import 'package:front_end/src/incremental/byte_store.dart';
44 import 'package:linter/src/rules.dart' as linter; 44 import 'package:linter/src/rules.dart' as linter;
45 import 'package:meta/meta.dart';
45 import 'package:package_config/discovery.dart' as pkg_discovery; 46 import 'package:package_config/discovery.dart' as pkg_discovery;
46 import 'package:package_config/packages.dart' show Packages; 47 import 'package:package_config/packages.dart' show Packages;
47 import 'package:package_config/packages_file.dart' as pkgfile show parse; 48 import 'package:package_config/packages_file.dart' as pkgfile show parse;
48 import 'package:package_config/src/packages_impl.dart' show MapPackages; 49 import 'package:package_config/src/packages_impl.dart' show MapPackages;
49 import 'package:path/path.dart' as path; 50 import 'package:path/path.dart' as path;
50 import 'package:plugin/manager.dart'; 51 import 'package:plugin/manager.dart';
51 import 'package:plugin/plugin.dart'; 52 import 'package:plugin/plugin.dart';
53 import 'package:telemetry/crash_reporting.dart';
54 import 'package:telemetry/telemetry.dart' as telemetry;
52 import 'package:yaml/yaml.dart'; 55 import 'package:yaml/yaml.dart';
53 56
54 /// Shared IO sink for standard error reporting. 57 /// Shared IO sink for standard error reporting.
55 /// 58 @visibleForTesting
56 /// *Visible for testing.*
57 StringSink errorSink = io.stderr; 59 StringSink errorSink = io.stderr;
58 60
59 /// Shared IO sink for standard out reporting. 61 /// Shared IO sink for standard out reporting.
60 /// 62 @visibleForTesting
61 /// *Visible for testing.*
62 StringSink outSink = io.stdout; 63 StringSink outSink = io.stdout;
63 64
64 /// Test this option map to see if it specifies lint rules. 65 /// Test this option map to see if it specifies lint rules.
65 bool containsLintRuleEntry(Map<String, YamlNode> options) { 66 bool containsLintRuleEntry(Map<String, YamlNode> options) {
66 var linterNode = options['linter']; 67 var linterNode = options['linter'];
67 return linterNode is YamlMap && linterNode.containsKey('rules'); 68 return linterNode is YamlMap && linterNode.containsKey('rules');
68 } 69 }
69 70
71 telemetry.Analytics _analytics;
72
73 const _analyticsID = 'UA-26406144-28';
74
75 /// The analytics instance for analyzer-cli.
76 telemetry.Analytics get analytics => (_analytics ??=
77 telemetry.createAnalyticsInstance(_analyticsID, 'analyzer-cli'));
78
79 /// Make sure that we create an analytics instance that doesn't send for this
80 /// session.
81 void disableAnalyticsForSession() {
82 _analytics = telemetry.createAnalyticsInstance(_analyticsID, 'analyzer-cli',
83 disableForSession: true);
84 }
85
86 @visibleForTesting
87 void setAnalytics(telemetry.Analytics replacementAnalytics) {
88 _analytics = replacementAnalytics;
89 }
90
70 class Driver implements CommandLineStarter { 91 class Driver implements CommandLineStarter {
71 static final PerformanceTag _analyzeAllTag = 92 static final PerformanceTag _analyzeAllTag =
72 new PerformanceTag("Driver._analyzeAll"); 93 new PerformanceTag("Driver._analyzeAll");
73 94
74 /// Cache of [AnalysisOptionsImpl] objects that correspond to directories 95 /// Cache of [AnalysisOptionsImpl] objects that correspond to directories
75 /// with analyzed files, used to reduce searching for `analysis_options.yaml` 96 /// with analyzed files, used to reduce searching for `analysis_options.yaml`
76 /// files. 97 /// files.
77 static Map<String, AnalysisOptionsImpl> _directoryToAnalysisOptions = {}; 98 static Map<String, AnalysisOptionsImpl> _directoryToAnalysisOptions = {};
78 99
79 static ByteStore analysisDriverMemoryByteStore = new MemoryByteStore(); 100 static ByteStore analysisDriverMemoryByteStore = new MemoryByteStore();
(...skipping 22 matching lines...) Expand all
102 123
103 /** 124 /**
104 * The resource provider used to access the file system. 125 * The resource provider used to access the file system.
105 */ 126 */
106 file_system.ResourceProvider resourceProvider = 127 file_system.ResourceProvider resourceProvider =
107 PhysicalResourceProvider.INSTANCE; 128 PhysicalResourceProvider.INSTANCE;
108 129
109 /// Collected analysis statistics. 130 /// Collected analysis statistics.
110 final AnalysisStats stats = new AnalysisStats(); 131 final AnalysisStats stats = new AnalysisStats();
111 132
133 CrashReportSender _crashReportSender;
134
135 // TODO(devoncarew): Replace with the real crash product ID.
136 /// The crash reporting instance for analyzer-cli.
137 CrashReportSender get crashReportSender => (_crashReportSender ??=
138 new CrashReportSender('Dart_analyzer_cli', analytics));
139
140 /// Create a new Driver instance.
141 ///
142 /// [isTesting] is true if we're running in a test environment.
143 Driver({bool isTesting: false}) {
144 if (isTesting) {
145 disableAnalyticsForSession();
146 }
147 }
148
112 /// This Driver's current analysis context. 149 /// This Driver's current analysis context.
113 /// 150 @visibleForTesting
114 /// *Visible for testing.*
115 AnalysisContext get context => _context; 151 AnalysisContext get context => _context;
116 152
117 @override 153 @override
118 void set userDefinedPlugins(List<Plugin> plugins) { 154 void set userDefinedPlugins(List<Plugin> plugins) {
119 _userDefinedPlugins = plugins ?? <Plugin>[]; 155 _userDefinedPlugins = plugins ?? <Plugin>[];
120 } 156 }
121 157
122 @override 158 @override
123 Future<Null> start(List<String> args) async { 159 Future<Null> start(List<String> args) async {
124 if (_context != null) { 160 if (_context != null) {
125 throw new StateError("start() can only be called once"); 161 throw new StateError("start() can only be called once");
126 } 162 }
127 int startTime = new DateTime.now().millisecondsSinceEpoch; 163 int startTime = new DateTime.now().millisecondsSinceEpoch;
128 164
129 StringUtilities.INTERNER = new MappedInterner(); 165 StringUtilities.INTERNER = new MappedInterner();
130 166
131 _processPlugins(); 167 _processPlugins();
132 168
133 // Parse commandline options. 169 // Parse commandline options.
134 CommandLineOptions options = CommandLineOptions.parse(args); 170 CommandLineOptions options = CommandLineOptions.parse(args);
135 171
172 if (options.batchMode || options.buildMode) {
173 disableAnalyticsForSession();
174 }
175
176 // Ping analytics with our initial call.
177 analytics.sendScreenView('home');
178
179 var timer = analytics.startTimer('analyze');
180
136 // Do analysis. 181 // Do analysis.
137 if (options.buildMode) { 182 if (options.buildMode) {
138 ErrorSeverity severity = _buildModeAnalyze(options); 183 ErrorSeverity severity = _buildModeAnalyze(options);
139 // Propagate issues to the exit code. 184 // Propagate issues to the exit code.
140 if (_shouldBeFatal(severity, options)) { 185 if (_shouldBeFatal(severity, options)) {
141 io.exitCode = severity.ordinal; 186 io.exitCode = severity.ordinal;
142 } 187 }
143 } else if (options.shouldBatch) { 188 } else if (options.batchMode) {
144 BatchRunner batchRunner = new BatchRunner(outSink, errorSink); 189 BatchRunner batchRunner = new BatchRunner(outSink, errorSink);
145 batchRunner.runAsBatch(args, (List<String> args) async { 190 batchRunner.runAsBatch(args, (List<String> args) async {
146 CommandLineOptions options = CommandLineOptions.parse(args); 191 CommandLineOptions options = CommandLineOptions.parse(args);
147 return await _analyzeAll(options); 192 return await _analyzeAll(options);
148 }); 193 });
149 } else { 194 } else {
150 ErrorSeverity severity = await _analyzeAll(options); 195 ErrorSeverity severity = await _analyzeAll(options);
151 // Propagate issues to the exit code. 196 // Propagate issues to the exit code.
152 if (_shouldBeFatal(severity, options)) { 197 if (_shouldBeFatal(severity, options)) {
153 io.exitCode = severity.ordinal; 198 io.exitCode = severity.ordinal;
154 } 199 }
155 } 200 }
156 201
157 if (_context != null) { 202 if (_context != null) {
158 _analyzedFileCount += _context.sources.length; 203 _analyzedFileCount += _context.sources.length;
159 } 204 }
160 205
206 // Send how long analysis took.
207 timer.finish();
208
209 // Send how many files were analyzed.
210 analytics.sendEvent('analyze', 'fileCount', value: _analyzedFileCount);
211
161 if (options.perfReport != null) { 212 if (options.perfReport != null) {
162 String json = makePerfReport( 213 String json = makePerfReport(
163 startTime, currentTimeMillis, options, _analyzedFileCount, stats); 214 startTime, currentTimeMillis, options, _analyzedFileCount, stats);
164 new io.File(options.perfReport).writeAsStringSync(json); 215 new io.File(options.perfReport).writeAsStringSync(json);
165 } 216 }
217
218 // Wait a brief time for any analytics calls to finish.
219 await analytics.waitForLastPing(timeout: new Duration(milliseconds: 200));
220 analytics.close();
166 } 221 }
167 222
168 Future<ErrorSeverity> _analyzeAll(CommandLineOptions options) async { 223 Future<ErrorSeverity> _analyzeAll(CommandLineOptions options) async {
169 PerformanceTag previous = _analyzeAllTag.makeCurrent(); 224 PerformanceTag previous = _analyzeAllTag.makeCurrent();
170 try { 225 try {
171 return await _analyzeAllImpl(options); 226 return await _analyzeAllImpl(options);
227 } catch (e, st) {
228 crashReportSender.sendReport(e, stackTrace: st);
229 rethrow;
172 } finally { 230 } finally {
173 previous.makeCurrent(); 231 previous.makeCurrent();
174 } 232 }
175 } 233 }
176 234
177 /// Perform analysis according to the given [options]. 235 /// Perform analysis according to the given [options].
178 Future<ErrorSeverity> _analyzeAllImpl(CommandLineOptions options) async { 236 Future<ErrorSeverity> _analyzeAllImpl(CommandLineOptions options) async {
179 if (!options.machineFormat) { 237 if (!options.machineFormat) {
180 List<String> fileNames = options.sourceFiles.map((String file) { 238 List<String> fileNames = options.sourceFiles.map((String file) {
181 file = path.normalize(file); 239 file = path.normalize(file);
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
314 return new BuildMode(resourceProvider, options, stats).analyze(); 372 return new BuildMode(resourceProvider, options, stats).analyze();
315 } 373 }
316 }); 374 });
317 } 375 }
318 376
319 /// Decide on the appropriate policy for which files need to be fully parsed 377 /// Decide on the appropriate policy for which files need to be fully parsed
320 /// and which files need to be diet parsed, based on [options], and return an 378 /// and which files need to be diet parsed, based on [options], and return an
321 /// [AnalyzeFunctionBodiesPredicate] that implements this policy. 379 /// [AnalyzeFunctionBodiesPredicate] that implements this policy.
322 AnalyzeFunctionBodiesPredicate _chooseDietParsingPolicy( 380 AnalyzeFunctionBodiesPredicate _chooseDietParsingPolicy(
323 CommandLineOptions options) { 381 CommandLineOptions options) {
324 if (options.shouldBatch) { 382 if (options.batchMode) {
325 // As analyzer is currently implemented, once a file has been diet 383 // As analyzer is currently implemented, once a file has been diet
326 // parsed, it can't easily be un-diet parsed without creating a brand new 384 // parsed, it can't easily be un-diet parsed without creating a brand new
327 // context and losing caching. In batch mode, we can't predict which 385 // context and losing caching. In batch mode, we can't predict which
328 // files we'll need to generate errors and warnings for in the future, so 386 // files we'll need to generate errors and warnings for in the future, so
329 // we can't safely diet parse anything. 387 // we can't safely diet parse anything.
330 return (Source source) => true; 388 return (Source source) => true;
331 } 389 }
332 390
333 return (Source source) { 391 return (Source source) {
334 if (options.sourceFiles.contains(source.fullName)) { 392 if (options.sourceFiles.contains(source.fullName)) {
(...skipping 597 matching lines...) Expand 10 before | Expand all | Expand 10 after
932 for (var package in packages) { 990 for (var package in packages) {
933 var packageName = path.basename(package.path); 991 var packageName = path.basename(package.path);
934 var realPath = package.resolveSymbolicLinksSync(); 992 var realPath = package.resolveSymbolicLinksSync();
935 result[packageName] = [ 993 result[packageName] = [
936 PhysicalResourceProvider.INSTANCE.getFolder(realPath) 994 PhysicalResourceProvider.INSTANCE.getFolder(realPath)
937 ]; 995 ];
938 } 996 }
939 return result; 997 return result;
940 } 998 }
941 } 999 }
OLDNEW
« no previous file with comments | « pkg/analyzer_cli/lib/src/build_mode.dart ('k') | pkg/analyzer_cli/lib/src/options.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698