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

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

Issue 2963323002: Add analytics to analyzer-cli and analysis server. (Closed)
Patch Set: 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
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 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
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:package_config/discovery.dart' as pkg_discovery; 45 import 'package:package_config/discovery.dart' as pkg_discovery;
46 import 'package:package_config/packages.dart' show Packages; 46 import 'package:package_config/packages.dart' show Packages;
47 import 'package:package_config/packages_file.dart' as pkgfile show parse; 47 import 'package:package_config/packages_file.dart' as pkgfile show parse;
48 import 'package:package_config/src/packages_impl.dart' show MapPackages; 48 import 'package:package_config/src/packages_impl.dart' show MapPackages;
49 import 'package:path/path.dart' as path; 49 import 'package:path/path.dart' as path;
50 import 'package:plugin/manager.dart'; 50 import 'package:plugin/manager.dart';
51 import 'package:plugin/plugin.dart'; 51 import 'package:plugin/plugin.dart';
52 import 'package:telemetry/crash_reporting.dart';
53 import 'package:telemetry/telemetry.dart' as telemetry;
52 import 'package:yaml/yaml.dart'; 54 import 'package:yaml/yaml.dart';
53 55
54 /// Shared IO sink for standard error reporting. 56 /// Shared IO sink for standard error reporting.
55 /// 57 ///
56 /// *Visible for testing.* 58 /// *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 ///
61 /// *Visible for testing.* 63 /// *Visible for testing.*
62 StringSink outSink = io.stdout; 64 StringSink outSink = io.stdout;
63 65
64 /// Test this option map to see if it specifies lint rules. 66 /// Test this option map to see if it specifies lint rules.
65 bool containsLintRuleEntry(Map<String, YamlNode> options) { 67 bool containsLintRuleEntry(Map<String, YamlNode> options) {
66 var linterNode = options['linter']; 68 var linterNode = options['linter'];
67 return linterNode is YamlMap && linterNode.containsKey('rules'); 69 return linterNode is YamlMap && linterNode.containsKey('rules');
68 } 70 }
69 71
72 telemetry.Analytics _analytics;
73
74 // TODO(devoncarew): Replace with the real tracking ID.
75 const _analyticsID = 'UA-001';
76
77 /// The analytics instance for analyzer-cli.
78 telemetry.Analytics get analytics => (_analytics ??=
79 telemetry.createAnalyticsInstance(_analyticsID, 'analyzer-cli'));
80
81 /// Make sure that we create an analytics instance that doesn't send for this
82 /// session.
83 void disableAnalyticsForSession() {
84 _analytics = telemetry.createAnalyticsInstance(_analyticsID, 'analyzer-cli',
85 disableForSession: true);
86 }
87
88 /// Public for testing.
Brian Wilkerson 2017/06/30 18:51:22 Please use the annotation `visibleForTesting` (fro
devoncarew 2017/06/30 21:58:13 Updated!
89 void setAnalyticsMock(telemetry.Analytics replacementAnalytics) {
90 _analytics = replacementAnalytics;
91 }
92
70 class Driver implements CommandLineStarter { 93 class Driver implements CommandLineStarter {
71 static final PerformanceTag _analyzeAllTag = 94 static final PerformanceTag _analyzeAllTag =
72 new PerformanceTag("Driver._analyzeAll"); 95 new PerformanceTag("Driver._analyzeAll");
73 96
74 /// Cache of [AnalysisOptionsImpl] objects that correspond to directories 97 /// Cache of [AnalysisOptionsImpl] objects that correspond to directories
75 /// with analyzed files, used to reduce searching for `analysis_options.yaml` 98 /// with analyzed files, used to reduce searching for `analysis_options.yaml`
76 /// files. 99 /// files.
77 static Map<String, AnalysisOptionsImpl> _directoryToAnalysisOptions = {}; 100 static Map<String, AnalysisOptionsImpl> _directoryToAnalysisOptions = {};
78 101
79 static ByteStore analysisDriverMemoryByteStore = new MemoryByteStore(); 102 static ByteStore analysisDriverMemoryByteStore = new MemoryByteStore();
(...skipping 22 matching lines...) Expand all
102 125
103 /** 126 /**
104 * The resource provider used to access the file system. 127 * The resource provider used to access the file system.
105 */ 128 */
106 file_system.ResourceProvider resourceProvider = 129 file_system.ResourceProvider resourceProvider =
107 PhysicalResourceProvider.INSTANCE; 130 PhysicalResourceProvider.INSTANCE;
108 131
109 /// Collected analysis statistics. 132 /// Collected analysis statistics.
110 final AnalysisStats stats = new AnalysisStats(); 133 final AnalysisStats stats = new AnalysisStats();
111 134
135 CrashReportSender _crashReportSender;
136
137 // TODO(devoncarew): Replace with the real crash product ID.
138 /// The crash reporting instance for analyzer-cli.
139 CrashReportSender get crashReportSender => (_crashReportSender ??=
140 new CrashReportSender('Dart-analyzer-cli', analytics));
141
142 /// Create a new Driver instance.
143 ///
144 /// [isTesting] is true is we're running in a test environment.
Brian Wilkerson 2017/06/30 18:51:22 "true is" --> "true if"
devoncarew 2017/06/30 21:58:13 Done.
145 Driver({bool isTesting: false}) {
146 if (isTesting) {
147 disableAnalyticsForSession();
148 }
149 }
150
112 /// This Driver's current analysis context. 151 /// This Driver's current analysis context.
113 /// 152 ///
114 /// *Visible for testing.* 153 /// *Visible for testing.*
115 AnalysisContext get context => _context; 154 AnalysisContext get context => _context;
116 155
117 @override 156 @override
118 void set userDefinedPlugins(List<Plugin> plugins) { 157 void set userDefinedPlugins(List<Plugin> plugins) {
119 _userDefinedPlugins = plugins ?? <Plugin>[]; 158 _userDefinedPlugins = plugins ?? <Plugin>[];
120 } 159 }
121 160
122 @override 161 @override
123 Future<Null> start(List<String> args) async { 162 Future<Null> start(List<String> args) async {
124 if (_context != null) { 163 if (_context != null) {
125 throw new StateError("start() can only be called once"); 164 throw new StateError("start() can only be called once");
126 } 165 }
127 int startTime = new DateTime.now().millisecondsSinceEpoch; 166 int startTime = new DateTime.now().millisecondsSinceEpoch;
128 167
129 StringUtilities.INTERNER = new MappedInterner(); 168 StringUtilities.INTERNER = new MappedInterner();
130 169
131 _processPlugins(); 170 _processPlugins();
132 171
133 // Parse commandline options. 172 // Parse commandline options.
134 CommandLineOptions options = CommandLineOptions.parse(args); 173 CommandLineOptions options = CommandLineOptions.parse(args);
135 174
175 if (options.batchMode || options.buildMode) {
176 disableAnalyticsForSession();
177 }
178
179 // Ping analytics with our initial call.
180 analytics.sendScreenView('home');
181
182 var timer = analytics.startTimer('analyze');
183
136 // Do analysis. 184 // Do analysis.
137 if (options.buildMode) { 185 if (options.buildMode) {
138 ErrorSeverity severity = _buildModeAnalyze(options); 186 ErrorSeverity severity = _buildModeAnalyze(options);
139 // Propagate issues to the exit code. 187 // Propagate issues to the exit code.
140 if (_shouldBeFatal(severity, options)) { 188 if (_shouldBeFatal(severity, options)) {
141 io.exitCode = severity.ordinal; 189 io.exitCode = severity.ordinal;
142 } 190 }
143 } else if (options.shouldBatch) { 191 } else if (options.batchMode) {
144 BatchRunner batchRunner = new BatchRunner(outSink, errorSink); 192 BatchRunner batchRunner = new BatchRunner(outSink, errorSink);
145 batchRunner.runAsBatch(args, (List<String> args) async { 193 batchRunner.runAsBatch(args, (List<String> args) async {
146 CommandLineOptions options = CommandLineOptions.parse(args); 194 CommandLineOptions options = CommandLineOptions.parse(args);
147 return await _analyzeAll(options); 195 return await _analyzeAll(options);
148 }); 196 });
149 } else { 197 } else {
150 ErrorSeverity severity = await _analyzeAll(options); 198 ErrorSeverity severity = await _analyzeAll(options);
151 // Propagate issues to the exit code. 199 // Propagate issues to the exit code.
152 if (_shouldBeFatal(severity, options)) { 200 if (_shouldBeFatal(severity, options)) {
153 io.exitCode = severity.ordinal; 201 io.exitCode = severity.ordinal;
154 } 202 }
155 } 203 }
156 204
157 if (_context != null) { 205 if (_context != null) {
158 _analyzedFileCount += _context.sources.length; 206 _analyzedFileCount += _context.sources.length;
159 } 207 }
160 208
209 // Send how long analysis took.
210 timer.finish();
211
212 // Send how many files were analyzed.
213 analytics.sendEvent('analyze', 'analyzedFiles', value: _analyzedFileCount);
214
161 if (options.perfReport != null) { 215 if (options.perfReport != null) {
162 String json = makePerfReport( 216 String json = makePerfReport(
163 startTime, currentTimeMillis, options, _analyzedFileCount, stats); 217 startTime, currentTimeMillis, options, _analyzedFileCount, stats);
164 new io.File(options.perfReport).writeAsStringSync(json); 218 new io.File(options.perfReport).writeAsStringSync(json);
165 } 219 }
220
221 // Wait a brief time for any analytics calls to finish.
222 await analytics.waitForLastPing(timeout: new Duration(milliseconds: 200));
166 } 223 }
167 224
168 Future<ErrorSeverity> _analyzeAll(CommandLineOptions options) async { 225 Future<ErrorSeverity> _analyzeAll(CommandLineOptions options) async {
169 PerformanceTag previous = _analyzeAllTag.makeCurrent(); 226 PerformanceTag previous = _analyzeAllTag.makeCurrent();
170 try { 227 try {
171 return await _analyzeAllImpl(options); 228 return await _analyzeAllImpl(options);
229 } catch (e, st) {
230 crashReportSender.sendReport(e, stackTrace: st);
231 rethrow;
172 } finally { 232 } finally {
173 previous.makeCurrent(); 233 previous.makeCurrent();
174 } 234 }
175 } 235 }
176 236
177 /// Perform analysis according to the given [options]. 237 /// Perform analysis according to the given [options].
178 Future<ErrorSeverity> _analyzeAllImpl(CommandLineOptions options) async { 238 Future<ErrorSeverity> _analyzeAllImpl(CommandLineOptions options) async {
179 if (!options.machineFormat) { 239 if (!options.machineFormat) {
180 List<String> fileNames = options.sourceFiles.map((String file) { 240 List<String> fileNames = options.sourceFiles.map((String file) {
181 file = path.normalize(file); 241 file = path.normalize(file);
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
314 return new BuildMode(resourceProvider, options, stats).analyze(); 374 return new BuildMode(resourceProvider, options, stats).analyze();
315 } 375 }
316 }); 376 });
317 } 377 }
318 378
319 /// Decide on the appropriate policy for which files need to be fully parsed 379 /// 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 380 /// and which files need to be diet parsed, based on [options], and return an
321 /// [AnalyzeFunctionBodiesPredicate] that implements this policy. 381 /// [AnalyzeFunctionBodiesPredicate] that implements this policy.
322 AnalyzeFunctionBodiesPredicate _chooseDietParsingPolicy( 382 AnalyzeFunctionBodiesPredicate _chooseDietParsingPolicy(
323 CommandLineOptions options) { 383 CommandLineOptions options) {
324 if (options.shouldBatch) { 384 if (options.batchMode) {
325 // As analyzer is currently implemented, once a file has been diet 385 // 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 386 // 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 387 // 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 388 // files we'll need to generate errors and warnings for in the future, so
329 // we can't safely diet parse anything. 389 // we can't safely diet parse anything.
330 return (Source source) => true; 390 return (Source source) => true;
331 } 391 }
332 392
333 return (Source source) { 393 return (Source source) {
334 if (options.sourceFiles.contains(source.fullName)) { 394 if (options.sourceFiles.contains(source.fullName)) {
(...skipping 597 matching lines...) Expand 10 before | Expand all | Expand 10 after
932 for (var package in packages) { 992 for (var package in packages) {
933 var packageName = path.basename(package.path); 993 var packageName = path.basename(package.path);
934 var realPath = package.resolveSymbolicLinksSync(); 994 var realPath = package.resolveSymbolicLinksSync();
935 result[packageName] = [ 995 result[packageName] = [
936 PhysicalResourceProvider.INSTANCE.getFolder(realPath) 996 PhysicalResourceProvider.INSTANCE.getFolder(realPath)
937 ]; 997 ];
938 } 998 }
939 return result; 999 return result;
940 } 1000 }
941 } 1001 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698