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

Side by Side Diff: packages/usage/lib/usage.dart

Issue 2990843002: Removed fixed dependencies (Closed)
Patch Set: Created 3 years, 4 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 | « packages/usage/lib/src/uuid.dart ('k') | packages/usage/lib/usage_html.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) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, 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 /** 5 /**
6 * `usage` is a wrapper around Google Analytics for both command-line apps 6 * `usage` is a wrapper around Google Analytics for both command-line apps
7 * and web apps. 7 * and web apps.
8 * 8 *
9 * In order to use this library as a web app, import the `analytics_html.dart` 9 * In order to use this library as a web app, import the `analytics_html.dart`
10 * library and instantiate the [AnalyticsHtml] class. 10 * library and instantiate the [AnalyticsHtml] class.
(...skipping 11 matching lines...) Expand all
22 * For more information, please see the Google Analytics Measurement Protocol 22 * For more information, please see the Google Analytics Measurement Protocol
23 * [Policy](https://developers.google.com/analytics/devguides/collection/protoco l/policy). 23 * [Policy](https://developers.google.com/analytics/devguides/collection/protoco l/policy).
24 */ 24 */
25 library usage; 25 library usage;
26 26
27 import 'dart:async'; 27 import 'dart:async';
28 28
29 // Matches file:/, non-ws, /, non-ws, .dart 29 // Matches file:/, non-ws, /, non-ws, .dart
30 final RegExp _pathRegex = new RegExp(r'file:/\S+/(\S+\.dart)'); 30 final RegExp _pathRegex = new RegExp(r'file:/\S+/(\S+\.dart)');
31 31
32 // Match multiple tabs or spaces.
33 final RegExp _tabOrSpaceRegex = new RegExp(r'[\t ]+');
34
35 /** 32 /**
36 * An interface to a Google Analytics session. [AnalyticsHtml] and [AnalyticsIO] 33 * An interface to a Google Analytics session. [AnalyticsHtml] and [AnalyticsIO]
37 * are concrete implementations of this interface. [AnalyticsMock] can be used 34 * are concrete implementations of this interface. [AnalyticsMock] can be used
38 * for testing or for some variants of an opt-in workflow. 35 * for testing or for some varients of an opt-in workflow.
39 * 36 *
40 * The analytics information is sent on a best-effort basis. So, failures to 37 * The analytics information is sent on a best-effort basis. So, failures to
41 * send the GA information will not result in errors from the asynchronous 38 * send the GA information will not result in errors from the asynchronous
42 * `send` methods. 39 * `send` methods.
43 */ 40 */
44 abstract class Analytics { 41 abstract class Analytics {
45 /** 42 /**
46 * Tracking ID / Property ID. 43 * Tracking ID / Property ID.
47 */ 44 */
48 String get trackingId; 45 String get trackingId;
49 46
50 /// The application name. 47 /**
51 String get applicationName; 48 * Whether the user has opt-ed in to additional analytics.
49 */
50 bool get optIn;
52 51
53 /// The application version. 52 set optIn(bool value);
54 String get applicationVersion;
55 53
56 /** 54 /**
57 * Is this the first time the tool has run? 55 * Whether the [optIn] value has been explicitly set (either `true` or
56 * `false`).
58 */ 57 */
59 bool get firstRun; 58 bool get hasSetOptIn;
60
61 /**
62 * Whether the [Analytics] instance is configured in an opt-in or opt-out mann er.
63 */
64 AnalyticsOpt analyticsOpt = AnalyticsOpt.optOut;
65
66 /**
67 * Will analytics data be sent.
68 */
69 bool get enabled;
70
71 /**
72 * Enable or disable sending of analytics data.
73 */
74 set enabled(bool value);
75
76 /**
77 * Anonymous client ID in UUID v4 format.
78 *
79 * The value is randomly-generated and should be reasonably stable for the
80 * computer sending analytics data.
81 */
82 String get clientId;
83 59
84 /** 60 /**
85 * Sends a screen view hit to Google Analytics. 61 * Sends a screen view hit to Google Analytics.
86 *
87 * [parameters] can be any analytics key/value pair. Useful
88 * for custom dimensions, etc.
89 */ 62 */
90 Future sendScreenView(String viewName, {Map<String, String> parameters}); 63 Future sendScreenView(String viewName);
91 64
92 /** 65 /**
93 * Sends an Event hit to Google Analytics. [label] specifies the event label. 66 * Sends an Event hit to Google Analytics. [label] specifies the event label.
94 * [value] specifies the event value. Values must be non-negative. 67 * [value] specifies the event value. Values must be non-negative.
95 *
96 * [parameters] can be any analytics key/value pair. Useful
97 * for custom dimensions, etc.
98 */ 68 */
99 Future sendEvent(String category, String action, 69 Future sendEvent(String category, String action, {String label, int value});
100 {String label, int value, Map<String, String> parameters});
101 70
102 /** 71 /**
103 * Sends a Social hit to Google Analytics. [network] specifies the social 72 * Sends a Social hit to Google Analytics. [network] specifies the social
104 * network, for example Facebook or Google Plus. [action] specifies the social 73 * network, for example Facebook or Google Plus. [action] specifies the social
105 * interaction action. For example on Google Plus when a user clicks the +1 74 * interaction action. For example on Google Plus when a user clicks the +1
106 * button, the social action is 'plus'. [target] specifies the target of a 75 * button, the social action is 'plus'. [target] specifies the target of a
107 * social interaction. This value is typically a URL but can be any text. 76 * social interaction. This value is typically a URL but can be any text.
108 */ 77 */
109 Future sendSocial(String network, String action, String target); 78 Future sendSocial(String network, String action, String target);
110 79
111 /** 80 /**
112 * Sends a Timing hit to Google Analytics. [variableName] specifies the 81 * Sends a Timing hit to Google Analytics. [variableName] specifies the
113 * variable name of the timing. [time] specifies the user timing value (in 82 * variable name of the timing. [time] specifies the user timing value (in
114 * milliseconds). [category] specifies the category of the timing. [label] 83 * milliseconds). [category] specifies the category of the timing. [label]
115 * specifies the label of the timing. 84 * specifies the label of the timing.
116 */ 85 */
117 Future sendTiming(String variableName, int time, 86 Future sendTiming(String variableName, int time, {String category,
118 {String category, String label}); 87 String label});
119 88
120 /** 89 /**
121 * Start a timer. The time won't be calculated, and the analytics information 90 * Start a timer. The time won't be calculated, and the analytics information
122 * sent, until the [AnalyticsTimer.finish] method is called. 91 * sent, until the [AnalyticsTimer.finish] method is called.
123 */ 92 */
124 AnalyticsTimer startTimer(String variableName, 93 AnalyticsTimer startTimer(String variableName,
125 {String category, String label}); 94 {String category, String label});
126 95
127 /** 96 /**
128 * In order to avoid sending any personally identifying information, the 97 * In order to avoid sending any personally identifying information, the
129 * [description] field must not contain the exception message. In addition, 98 * [description] field must not contain the exception message. In addition,
130 * only the first 100 chars of the description will be sent. 99 * only the first 100 chars of the description will be sent.
131 */ 100 */
132 Future sendException(String description, {bool fatal}); 101 Future sendException(String description, {bool fatal});
133 102
134 /** 103 /**
135 * Gets a session variable value.
136 */
137 dynamic getSessionValue(String param);
138
139 /**
140 * Sets a session variable value. The value is persistent for the life of the 104 * Sets a session variable value. The value is persistent for the life of the
141 * [Analytics] instance. This variable will be sent in with every analytics 105 * [Analytics] instance. This variable will be sent in with every analytics
142 * hit. A list of valid variable names can be found here: 106 * hit. A list of valid variable names can be found here:
143 * https://developers.google.com/analytics/devguides/collection/protocol/v1/pa rameters. 107 * https://developers.google.com/analytics/devguides/collection/protocol/v1/pa rameters.
144 */ 108 */
145 void setSessionValue(String param, dynamic value); 109 void setSessionValue(String param, dynamic value);
146 110
147 /** 111 /**
148 * Fires events when the usage library sends any data over the network. This
149 * will not fire if analytics has been disabled or if the throttling algorithm
150 * has been engaged.
151 *
152 * This method is public to allow library clients to more easily test their
153 * analytics implementations.
154 */
155 Stream<Map<String, dynamic>> get onSend;
156
157 /**
158 * Wait for all of the outstanding analytics pings to complete. The returned 112 * Wait for all of the outstanding analytics pings to complete. The returned
159 * `Future` will always complete without errors. You can pass in an optional 113 * `Future` will always complete without errors. You can pass in an optional
160 * `Duration` to specify to only wait for a certain amount of time. 114 * `Duration` to specify to only wait for a certain amount of time.
161 * 115 *
162 * This method is particularly useful for command-line clients. Outstanding 116 * This method is particularly useful for command-line clients. Outstanding
163 * I/O requests will cause the VM to delay terminating the process. Generally, 117 * I/O requests will cause the VM to delay terminating the process. Generally,
164 * users won't want their CLI app to pause at the end of the process waiting 118 * users won't want their CLI app to pause at the end of the process waiting
165 * for Google analytics requests to complete. This method allows CLI apps to 119 * for Google analytics requests to complete. This method allows CLI apps to
166 * delay for a short time waiting for GA requests to complete, and then do 120 * delay for a short time waiting for GA requests to complete, and then do
167 * something like call `dart:io`'s `exit()` explicitly themselves (or the 121 * something like call `exit()` explicitly themselves.
168 * [close] method below).
169 */ 122 */
170 Future waitForLastPing({Duration timeout}); 123 Future waitForLastPing({Duration timeout});
171
172 /// Free any used resources.
173 ///
174 /// The [Analytics] instance should not be used after this call.
175 void close();
176 }
177
178 enum AnalyticsOpt {
179 /**
180 * Users must opt-in before any analytics data is sent.
181 */
182 optIn,
183
184 /**
185 * Users must opt-out for analytics data to not be sent.
186 */
187 optOut
188 } 124 }
189 125
190 /** 126 /**
191 * An object, returned by [Analytics.startTimer], that is used to measure an 127 * An object, returned by [Analytics.startTimer], that is used to measure an
192 * asynchronous process. 128 * asynchronous process.
193 */ 129 */
194 class AnalyticsTimer { 130 class AnalyticsTimer {
195 final Analytics analytics; 131 final Analytics analytics;
196 final String variableName; 132 final String variableName;
197 final String category; 133 final String category;
(...skipping 16 matching lines...) Expand all
214 } 150 }
215 151
216 /** 152 /**
217 * Finish the timer, calculate the elapsed time, and send the information to 153 * Finish the timer, calculate the elapsed time, and send the information to
218 * analytics. Once this is called, any future invocations are no-ops. 154 * analytics. Once this is called, any future invocations are no-ops.
219 */ 155 */
220 Future finish() { 156 Future finish() {
221 if (_endMillis != null) return new Future.value(); 157 if (_endMillis != null) return new Future.value();
222 158
223 _endMillis = new DateTime.now().millisecondsSinceEpoch; 159 _endMillis = new DateTime.now().millisecondsSinceEpoch;
224 return analytics.sendTiming(variableName, currentElapsedMillis, 160 return analytics.sendTiming(
225 category: category, label: label); 161 variableName, currentElapsedMillis, category: category, label: label);
226 } 162 }
227 } 163 }
228 164
229 /** 165 /**
230 * A no-op implementation of the [Analytics] class. This can be used as a 166 * A no-op implementation of the [Analytics] class. This can be used as a
231 * stand-in for that will never ping the GA server, or as a mock in test code. 167 * stand-in for that will never ping the GA server, or as a mock in test code.
232 */ 168 */
233 class AnalyticsMock implements Analytics { 169 class AnalyticsMock implements Analytics {
234 @override
235 String get trackingId => 'UA-0'; 170 String get trackingId => 'UA-0';
236 @override
237 String get applicationName => 'mock-app';
238 @override
239 String get applicationVersion => '1.0.0';
240
241 final bool logCalls; 171 final bool logCalls;
242 172
243 /** 173 bool optIn = false;
244 * Events are never added to this controller for the mock implementation. 174 bool hasSetOptIn = true;
245 */
246 StreamController<Map<String, dynamic>> _sendController =
247 new StreamController.broadcast();
248 175
249 /** 176 /**
250 * Create a new [AnalyticsMock]. If [logCalls] is true, all calls will be 177 * Create a new [AnalyticsMock]. If [logCalls] is true, all calls will be
251 * logged to stdout. 178 * logged to stdout.
252 */ 179 */
253 AnalyticsMock([this.logCalls = false]); 180 AnalyticsMock([this.logCalls = false]);
254 181
255 @override 182 Future sendScreenView(String viewName) =>
256 bool get firstRun => false; 183 _log('screenView', {'viewName': viewName});
257 184
258 @override 185 Future sendEvent(String category, String action, {String label, int value}) {
259 AnalyticsOpt analyticsOpt = AnalyticsOpt.optOut; 186 return _log('event', {'category': category, 'action': action,
260 187 'label': label, 'value': value});
261 @override
262 bool enabled = true;
263
264 @override
265 String get clientId => '00000000-0000-4000-0000-000000000000';
266
267 @override
268 Future sendScreenView(String viewName, {Map<String, String> parameters}) {
269 parameters ??= <String, String>{};
270 parameters['viewName'] = viewName;
271 return _log('screenView', parameters);
272 } 188 }
273 189
274 @override
275 Future sendEvent(String category, String action,
276 {String label, int value, Map<String, String> parameters}) {
277 parameters ??= <String, String>{};
278 return _log(
279 'event',
280 {'category': category, 'action': action, 'label': label, 'value': value}
281 ..addAll(parameters));
282 }
283
284 @override
285 Future sendSocial(String network, String action, String target) => 190 Future sendSocial(String network, String action, String target) =>
286 _log('social', {'network': network, 'action': action, 'target': target}); 191 _log('social', {'network': network, 'action': action, 'target': target});
287 192
288 @override 193 Future sendTiming(String variableName, int time, {String category,
289 Future sendTiming(String variableName, int time, 194 String label}) {
290 {String category, String label}) { 195 return _log('timing', {'variableName': variableName, 'time': time,
291 return _log('timing', { 196 'category': category, 'label': label});
292 'variableName': variableName,
293 'time': time,
294 'category': category,
295 'label': label
296 });
297 } 197 }
298 198
299 @override
300 AnalyticsTimer startTimer(String variableName, 199 AnalyticsTimer startTimer(String variableName,
301 {String category, String label}) { 200 {String category, String label}) {
302 return new AnalyticsTimer(this, variableName, 201 return new AnalyticsTimer(this,
303 category: category, label: label); 202 variableName, category: category, label: label);
304 } 203 }
305 204
306 @override
307 Future sendException(String description, {bool fatal}) => 205 Future sendException(String description, {bool fatal}) =>
308 _log('exception', {'description': description, 'fatal': fatal}); 206 _log('exception', {'description': description, 'fatal': fatal});
309 207
310 @override 208 void setSessionValue(String param, dynamic value) { }
311 dynamic getSessionValue(String param) => null;
312 209
313 @override
314 void setSessionValue(String param, dynamic value) {}
315
316 @override
317 Stream<Map<String, dynamic>> get onSend => _sendController.stream;
318
319 @override
320 Future waitForLastPing({Duration timeout}) => new Future.value(); 210 Future waitForLastPing({Duration timeout}) => new Future.value();
321 211
322 @override
323 void close() {}
324
325 Future _log(String hitType, Map m) { 212 Future _log(String hitType, Map m) {
326 if (logCalls) { 213 if (logCalls) {
327 print('analytics: ${hitType} ${m}'); 214 print('analytics: ${hitType} ${m}');
328 } 215 }
329 216
330 return new Future.value(); 217 return new Future.value();
331 } 218 }
332 } 219 }
333 220
334 /** 221 /**
335 * Sanitize a stacktrace. This will shorten file paths in order to remove any 222 * Sanitize a stacktrace. This will shorten file paths in order to remove any
336 * PII that may be contained in the full file path. For example, this will 223 * PII that may be contained in the full file path. For example, this will
337 * shorten `file:///Users/foobar/tmp/error.dart` to `error.dart`. 224 * shorten `file:///Users/foobar/tmp/error.dart` to `error.dart`.
338 * 225 *
339 * If [shorten] is `true`, this method will also attempt to compress the text 226 * If [shorten] is `true`, this method will also attempt to compress the text
340 * of the stacktrace. GA has a 100 char limit on the text that can be sent for 227 * of the stacktrace. GA has a 100 char limit on the text that can be sent for
341 * an exception. This will try and make those first 100 chars contain 228 * an exception. This will try and make those first 100 chars contain
342 * information useful to debugging the issue. 229 * information useful to debugging the issue.
343 */ 230 */
344 String sanitizeStacktrace(dynamic st, {bool shorten: true}) { 231 String sanitizeStacktrace(dynamic st, {bool shorten: true}) {
345 String str = '${st}'; 232 String str = '${st}';
346 233
347 Iterable<Match> iter = _pathRegex.allMatches(str); 234 Iterable<Match> iter = _pathRegex.allMatches(str);
348 iter = iter.toList().reversed; 235 iter = iter.toList().reversed;
349 236
350 for (Match match in iter) { 237 for (Match match in iter) {
351 String replacement = match.group(1); 238 String replacement = match.group(1);
352 str = 239 str = str.substring(0, match.start)
353 str.substring(0, match.start) + replacement + str.substring(match.end); 240 + replacement + str.substring(match.end);
354 } 241 }
355 242
356 if (shorten) { 243 if (shorten) {
357 // Shorten the stacktrace up a bit. 244 // Shorten the stacktrace up a bit.
358 str = str.replaceAll(_tabOrSpaceRegex, ' '); 245 str = str
246 .replaceAll('(package:', '(')
247 .replaceAll('(dart:', '(')
248 .replaceAll(new RegExp(r'\s+'), ' ');
359 } 249 }
360 250
361 return str; 251 return str;
362 } 252 }
OLDNEW
« no previous file with comments | « packages/usage/lib/src/uuid.dart ('k') | packages/usage/lib/usage_html.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698