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

Unified Diff: packages/usage/lib/usage.dart

Issue 2989763002: Update charted to 0.4.8 and roll (Closed)
Patch Set: Removed Cutch from list of reviewers 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 side-by-side diff with in-line comments
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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: packages/usage/lib/usage.dart
diff --git a/packages/usage/lib/usage.dart b/packages/usage/lib/usage.dart
index 9a4279bbe37cbfcd418128a5cb15b154d3f6acc5..e79701cbe6b51fccbe996deb292e52fed7047261 100644
--- a/packages/usage/lib/usage.dart
+++ b/packages/usage/lib/usage.dart
@@ -29,10 +29,13 @@ import 'dart:async';
// Matches file:/, non-ws, /, non-ws, .dart
final RegExp _pathRegex = new RegExp(r'file:/\S+/(\S+\.dart)');
+// Match multiple tabs or spaces.
+final RegExp _tabOrSpaceRegex = new RegExp(r'[\t ]+');
+
/**
* An interface to a Google Analytics session. [AnalyticsHtml] and [AnalyticsIO]
* are concrete implementations of this interface. [AnalyticsMock] can be used
- * for testing or for some varients of an opt-in workflow.
+ * for testing or for some variants of an opt-in workflow.
*
* The analytics information is sent on a best-effort basis. So, failures to
* send the GA information will not result in errors from the asynchronous
@@ -44,27 +47,57 @@ abstract class Analytics {
*/
String get trackingId;
+ /// The application name.
+ String get applicationName;
+
+ /// The application version.
+ String get applicationVersion;
+
+ /**
+ * Is this the first time the tool has run?
+ */
+ bool get firstRun;
+
+ /**
+ * Whether the [Analytics] instance is configured in an opt-in or opt-out manner.
+ */
+ AnalyticsOpt analyticsOpt = AnalyticsOpt.optOut;
+
+ /**
+ * Will analytics data be sent.
+ */
+ bool get enabled;
+
/**
- * Whether the user has opt-ed in to additional analytics.
+ * Enable or disable sending of analytics data.
*/
- bool optIn;
+ set enabled(bool value);
/**
- * Whether the [optIn] value has been explicitly set (either `true` or
- * `false`).
+ * Anonymous client ID in UUID v4 format.
+ *
+ * The value is randomly-generated and should be reasonably stable for the
+ * computer sending analytics data.
*/
- bool get hasSetOptIn;
+ String get clientId;
/**
* Sends a screen view hit to Google Analytics.
+ *
+ * [parameters] can be any analytics key/value pair. Useful
+ * for custom dimensions, etc.
*/
- Future sendScreenView(String viewName);
+ Future sendScreenView(String viewName, {Map<String, String> parameters});
/**
* Sends an Event hit to Google Analytics. [label] specifies the event label.
* [value] specifies the event value. Values must be non-negative.
+ *
+ * [parameters] can be any analytics key/value pair. Useful
+ * for custom dimensions, etc.
*/
- Future sendEvent(String category, String action, {String label, int value});
+ Future sendEvent(String category, String action,
+ {String label, int value, Map<String, String> parameters});
/**
* Sends a Social hit to Google Analytics. [network] specifies the social
@@ -81,8 +114,8 @@ abstract class Analytics {
* milliseconds). [category] specifies the category of the timing. [label]
* specifies the label of the timing.
*/
- Future sendTiming(String variableName, int time, {String category,
- String label});
+ Future sendTiming(String variableName, int time,
+ {String category, String label});
/**
* Start a timer. The time won't be calculated, and the analytics information
@@ -98,6 +131,11 @@ abstract class Analytics {
*/
Future sendException(String description, {bool fatal});
+ /**
+ * Gets a session variable value.
+ */
+ dynamic getSessionValue(String param);
+
/**
* Sets a session variable value. The value is persistent for the life of the
* [Analytics] instance. This variable will be sent in with every analytics
@@ -106,6 +144,16 @@ abstract class Analytics {
*/
void setSessionValue(String param, dynamic value);
+ /**
+ * Fires events when the usage library sends any data over the network. This
+ * will not fire if analytics has been disabled or if the throttling algorithm
+ * has been engaged.
+ *
+ * This method is public to allow library clients to more easily test their
+ * analytics implementations.
+ */
+ Stream<Map<String, dynamic>> get onSend;
+
/**
* Wait for all of the outstanding analytics pings to complete. The returned
* `Future` will always complete without errors. You can pass in an optional
@@ -116,9 +164,27 @@ abstract class Analytics {
* users won't want their CLI app to pause at the end of the process waiting
* for Google analytics requests to complete. This method allows CLI apps to
* delay for a short time waiting for GA requests to complete, and then do
- * something like call `exit()` explicitly themselves.
+ * something like call `dart:io`'s `exit()` explicitly themselves (or the
+ * [close] method below).
*/
Future waitForLastPing({Duration timeout});
+
+ /// Free any used resources.
+ ///
+ /// The [Analytics] instance should not be used after this call.
+ void close();
+}
+
+enum AnalyticsOpt {
+ /**
+ * Users must opt-in before any analytics data is sent.
+ */
+ optIn,
+
+ /**
+ * Users must opt-out for analytics data to not be sent.
+ */
+ optOut
}
/**
@@ -155,8 +221,8 @@ class AnalyticsTimer {
if (_endMillis != null) return new Future.value();
_endMillis = new DateTime.now().millisecondsSinceEpoch;
- return analytics.sendTiming(
- variableName, currentElapsedMillis, category: category, label: label);
+ return analytics.sendTiming(variableName, currentElapsedMillis,
+ category: category, label: label);
}
}
@@ -165,11 +231,20 @@ class AnalyticsTimer {
* stand-in for that will never ping the GA server, or as a mock in test code.
*/
class AnalyticsMock implements Analytics {
+ @override
String get trackingId => 'UA-0';
+ @override
+ String get applicationName => 'mock-app';
+ @override
+ String get applicationVersion => '1.0.0';
+
final bool logCalls;
- bool optIn = false;
- bool hasSetOptIn = true;
+ /**
+ * Events are never added to this controller for the mock implementation.
+ */
+ StreamController<Map<String, dynamic>> _sendController =
+ new StreamController.broadcast();
/**
* Create a new [AnalyticsMock]. If [logCalls] is true, all calls will be
@@ -177,36 +252,76 @@ class AnalyticsMock implements Analytics {
*/
AnalyticsMock([this.logCalls = false]);
- Future sendScreenView(String viewName) =>
- _log('screenView', {'viewName': viewName});
+ @override
+ bool get firstRun => false;
+
+ @override
+ AnalyticsOpt analyticsOpt = AnalyticsOpt.optOut;
+
+ @override
+ bool enabled = true;
+
+ @override
+ String get clientId => '00000000-0000-4000-0000-000000000000';
+
+ @override
+ Future sendScreenView(String viewName, {Map<String, String> parameters}) {
+ parameters ??= <String, String>{};
+ parameters['viewName'] = viewName;
+ return _log('screenView', parameters);
+ }
- Future sendEvent(String category, String action, {String label, int value}) {
- return _log('event', {'category': category, 'action': action,
- 'label': label, 'value': value});
+ @override
+ Future sendEvent(String category, String action,
+ {String label, int value, Map<String, String> parameters}) {
+ parameters ??= <String, String>{};
+ return _log(
+ 'event',
+ {'category': category, 'action': action, 'label': label, 'value': value}
+ ..addAll(parameters));
}
+ @override
Future sendSocial(String network, String action, String target) =>
_log('social', {'network': network, 'action': action, 'target': target});
- Future sendTiming(String variableName, int time, {String category,
- String label}) {
- return _log('timing', {'variableName': variableName, 'time': time,
- 'category': category, 'label': label});
+ @override
+ Future sendTiming(String variableName, int time,
+ {String category, String label}) {
+ return _log('timing', {
+ 'variableName': variableName,
+ 'time': time,
+ 'category': category,
+ 'label': label
+ });
}
+ @override
AnalyticsTimer startTimer(String variableName,
{String category, String label}) {
- return new AnalyticsTimer(this,
- variableName, category: category, label: label);
+ return new AnalyticsTimer(this, variableName,
+ category: category, label: label);
}
+ @override
Future sendException(String description, {bool fatal}) =>
_log('exception', {'description': description, 'fatal': fatal});
- void setSessionValue(String param, dynamic value) { }
+ @override
+ dynamic getSessionValue(String param) => null;
+
+ @override
+ void setSessionValue(String param, dynamic value) {}
+ @override
+ Stream<Map<String, dynamic>> get onSend => _sendController.stream;
+
+ @override
Future waitForLastPing({Duration timeout}) => new Future.value();
+ @override
+ void close() {}
+
Future _log(String hitType, Map m) {
if (logCalls) {
print('analytics: ${hitType} ${m}');
@@ -234,16 +349,13 @@ String sanitizeStacktrace(dynamic st, {bool shorten: true}) {
for (Match match in iter) {
String replacement = match.group(1);
- str = str.substring(0, match.start)
- + replacement + str.substring(match.end);
+ str =
+ str.substring(0, match.start) + replacement + str.substring(match.end);
}
if (shorten) {
// Shorten the stacktrace up a bit.
- str = str
- .replaceAll('(package:', '(')
- .replaceAll('(dart:', '(')
- .replaceAll(new RegExp(r'\s+'), ' ');
+ str = str.replaceAll(_tabOrSpaceRegex, ' ');
}
return str;
« 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