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

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

Issue 1400473008: Roll Observatory packages and add a roll script (Closed) Base URL: git@github.com:dart-lang/observatory_pub_packages.git@master
Patch Set: Created 5 years, 2 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 | « usage/lib/src/uuid.dart ('k') | 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
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 /**
6 * `usage` is a wrapper around Google Analytics for both command-line apps
7 * and web apps.
8 *
9 * In order to use this library as a web app, import the `analytics_html.dart`
10 * library and instantiate the [AnalyticsHtml] class.
11 *
12 * In order to use this library as a command-line app, import the
13 * `analytics_io.dart` library and instantiate the [AnalyticsIO] class.
14 *
15 * For both classes, you need to provide a Google Analytics tracking ID, the
16 * application name, and the application version.
17 *
18 * Your application should provide an opt-in option for the user. If they
19 * opt-in, set the [optIn] field to `true`. This setting will persist across
20 * sessions automatically.
21 *
22 * For more information, please see the Google Analytics Measurement Protocol
23 * [Policy](https://developers.google.com/analytics/devguides/collection/protoco l/policy).
24 */
25 library usage;
26
27 import 'dart:async';
28
29 // Matches file:/, non-ws, /, non-ws, .dart
30 final RegExp _pathRegex = new RegExp(r'file:/\S+/(\S+\.dart)');
31
32 /**
33 * An interface to a Google Analytics session. [AnalyticsHtml] and [AnalyticsIO]
34 * are concrete implementations of this interface. [AnalyticsMock] can be used
35 * for testing or for some varients of an opt-in workflow.
36 *
37 * The analytics information is sent on a best-effort basis. So, failures to
38 * send the GA information will not result in errors from the asynchronous
39 * `send` methods.
40 */
41 abstract class Analytics {
42 /**
43 * Tracking ID / Property ID.
44 */
45 String get trackingId;
46
47 /**
48 * Whether the user has opt-ed in to additional analytics.
49 */
50 bool optIn;
51
52 /**
53 * Whether the [optIn] value has been explicitly set (either `true` or
54 * `false`).
55 */
56 bool get hasSetOptIn;
57
58 /**
59 * Sends a screen view hit to Google Analytics.
60 */
61 Future sendScreenView(String viewName);
62
63 /**
64 * Sends an Event hit to Google Analytics. [label] specifies the event label.
65 * [value] specifies the event value. Values must be non-negative.
66 */
67 Future sendEvent(String category, String action, {String label, int value});
68
69 /**
70 * Sends a Social hit to Google Analytics. [network] specifies the social
71 * network, for example Facebook or Google Plus. [action] specifies the social
72 * interaction action. For example on Google Plus when a user clicks the +1
73 * button, the social action is 'plus'. [target] specifies the target of a
74 * social interaction. This value is typically a URL but can be any text.
75 */
76 Future sendSocial(String network, String action, String target);
77
78 /**
79 * Sends a Timing hit to Google Analytics. [variableName] specifies the
80 * variable name of the timing. [time] specifies the user timing value (in
81 * milliseconds). [category] specifies the category of the timing. [label]
82 * specifies the label of the timing.
83 */
84 Future sendTiming(String variableName, int time, {String category,
85 String label});
86
87 /**
88 * Start a timer. The time won't be calculated, and the analytics information
89 * sent, until the [AnalyticsTimer.finish] method is called.
90 */
91 AnalyticsTimer startTimer(String variableName,
92 {String category, String label});
93
94 /**
95 * In order to avoid sending any personally identifying information, the
96 * [description] field must not contain the exception message. In addition,
97 * only the first 100 chars of the description will be sent.
98 */
99 Future sendException(String description, {bool fatal});
100
101 /**
102 * Sets a session variable value. The value is persistent for the life of the
103 * [Analytics] instance. This variable will be sent in with every analytics
104 * hit. A list of valid variable names can be found here:
105 * https://developers.google.com/analytics/devguides/collection/protocol/v1/pa rameters.
106 */
107 void setSessionValue(String param, dynamic value);
108
109 /**
110 * Wait for all of the outstanding analytics pings to complete. The returned
111 * `Future` will always complete without errors. You can pass in an optional
112 * `Duration` to specify to only wait for a certain amount of time.
113 *
114 * This method is particularly useful for command-line clients. Outstanding
115 * I/O requests will cause the VM to delay terminating the process. Generally,
116 * users won't want their CLI app to pause at the end of the process waiting
117 * for Google analytics requests to complete. This method allows CLI apps to
118 * delay for a short time waiting for GA requests to complete, and then do
119 * something like call `exit()` explicitly themselves.
120 */
121 Future waitForLastPing({Duration timeout});
122 }
123
124 /**
125 * An object, returned by [Analytics.startTimer], that is used to measure an
126 * asynchronous process.
127 */
128 class AnalyticsTimer {
129 final Analytics analytics;
130 final String variableName;
131 final String category;
132 final String label;
133
134 int _startMillis;
135 int _endMillis;
136
137 AnalyticsTimer(this.analytics, this.variableName,
138 {this.category, this.label}) {
139 _startMillis = new DateTime.now().millisecondsSinceEpoch;
140 }
141
142 int get currentElapsedMillis {
143 if (_endMillis == null) {
144 return new DateTime.now().millisecondsSinceEpoch - _startMillis;
145 } else {
146 return _endMillis - _startMillis;
147 }
148 }
149
150 /**
151 * Finish the timer, calculate the elapsed time, and send the information to
152 * analytics. Once this is called, any future invocations are no-ops.
153 */
154 Future finish() {
155 if (_endMillis != null) return new Future.value();
156
157 _endMillis = new DateTime.now().millisecondsSinceEpoch;
158 return analytics.sendTiming(
159 variableName, currentElapsedMillis, category: category, label: label);
160 }
161 }
162
163 /**
164 * A no-op implementation of the [Analytics] class. This can be used as a
165 * stand-in for that will never ping the GA server, or as a mock in test code.
166 */
167 class AnalyticsMock implements Analytics {
168 String get trackingId => 'UA-0';
169 final bool logCalls;
170
171 bool optIn = false;
172 bool hasSetOptIn = true;
173
174 /**
175 * Create a new [AnalyticsMock]. If [logCalls] is true, all calls will be
176 * logged to stdout.
177 */
178 AnalyticsMock([this.logCalls = false]);
179
180 Future sendScreenView(String viewName) =>
181 _log('screenView', {'viewName': viewName});
182
183 Future sendEvent(String category, String action, {String label, int value}) {
184 return _log('event', {'category': category, 'action': action,
185 'label': label, 'value': value});
186 }
187
188 Future sendSocial(String network, String action, String target) =>
189 _log('social', {'network': network, 'action': action, 'target': target});
190
191 Future sendTiming(String variableName, int time, {String category,
192 String label}) {
193 return _log('timing', {'variableName': variableName, 'time': time,
194 'category': category, 'label': label});
195 }
196
197 AnalyticsTimer startTimer(String variableName,
198 {String category, String label}) {
199 return new AnalyticsTimer(this,
200 variableName, category: category, label: label);
201 }
202
203 Future sendException(String description, {bool fatal}) =>
204 _log('exception', {'description': description, 'fatal': fatal});
205
206 void setSessionValue(String param, dynamic value) { }
207
208 Future waitForLastPing({Duration timeout}) => new Future.value();
209
210 Future _log(String hitType, Map m) {
211 if (logCalls) {
212 print('analytics: ${hitType} ${m}');
213 }
214
215 return new Future.value();
216 }
217 }
218
219 /**
220 * Sanitize a stacktrace. This will shorten file paths in order to remove any
221 * PII that may be contained in the full file path. For example, this will
222 * shorten `file:///Users/foobar/tmp/error.dart` to `error.dart`.
223 *
224 * If [shorten] is `true`, this method will also attempt to compress the text
225 * of the stacktrace. GA has a 100 char limit on the text that can be sent for
226 * an exception. This will try and make those first 100 chars contain
227 * information useful to debugging the issue.
228 */
229 String sanitizeStacktrace(dynamic st, {bool shorten: true}) {
230 String str = '${st}';
231
232 Iterable<Match> iter = _pathRegex.allMatches(str);
233 iter = iter.toList().reversed;
234
235 for (Match match in iter) {
236 String replacement = match.group(1);
237 str = str.substring(0, match.start)
238 + replacement + str.substring(match.end);
239 }
240
241 if (shorten) {
242 // Shorten the stacktrace up a bit.
243 str = str
244 .replaceAll('(package:', '(')
245 .replaceAll('(dart:', '(')
246 .replaceAll(new RegExp(r'\s+'), ' ');
247 }
248
249 return str;
250 }
OLDNEW
« no previous file with comments | « usage/lib/src/uuid.dart ('k') | usage/lib/usage_html.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698