This package is intended to be used on Dart and Flutter related tooling only. It provides APIs to send events to Google Analytics using the Measurement Protocol.

Usage

To get started using this package, import at the entrypoint dart file and initialize with the required parameters

IMPORTANT: It is best practice to close the http client connection when finished sending events, otherwise, you may notice that the dart process hangs on exit. The example below shows how to handle closing the connection via analytics.close() method.

Link to documentation for http client's close method

import 'unified_analytics/unified_analytics.dart';

// Constants that should be resolved by the client using package
final DashTool tool = DashTool.flutterTools; // Restricted to enum provided by package

// Values that need to be provided by the client that may
// need to be calculated
final String channel = ...;
final String flutterVersion = ...;
final String dartVersion = ...;

// Initialize the [Analytics] class with the required parameters;
// preferably outside of the [main] method
final Analytics analytics = Analytics(
  tool: tool,
  flutterChannel: channel,  // Optional; only if easy to determine
  flutterVersion: flutterVersion,  // Optional; only if easy to determine
  dartVersion: dartVersion,
);

// Timing a process and sending the event
void main() {
    DateTime start = DateTime.now();
    int count = 0;

    // Each client using this package will have it's own
    // method to show the message but the below is a trivial
    // example of how to properly initialize the analytics instance
    if (analytics.shouldShowMessage) {
      
      // Simulates displaying the message, this will vary from
      // client to client; ie. stdout, popup in IDE, etc.
      print(analytics.getConsentMessage);

      // After receiving confirmation that the message has been
      // displayed, invoking the below method will successfully
      // onboard the tool into the config file and allow for
      // events to be sent on the next creation of the analytics
      // instance
      //
      // The rest of the example below assumes that the tool has
      // already been onboarded in a previous run
      analytics.clientShowedMessage();
    }

    // Example of long running process
    for (int i = 0; i < 2000; i++) {
        count += i;
    }
    
    // Calculate the metric to send
    final int runTime = DateTime.now().difference(start).inMilliseconds;

    // Generate the body for the event data
    final Map<String, int> eventData = {
      'time_ns': runTime,
    };

    // Choose one of the enum values for [DashEvent] which should
    // have all possible events; if not there, open an issue for the
    // team to add
    final DashEvent eventName = ...; // Select appropriate DashEvent enum value

    // Make a call to the [Analytics] api to send the data
    analytics.sendEvent(
      eventName: eventName,
      eventData: eventData,
    );

    // Close the client connection on exit
    analytics.close();
}

Opting In and Out of Analytics Collection

It will be important for each tool to expose a trivial method to disabling or enabling analytics collection. Based on how the user interacts with the tool, this can be done through the CLI, IDE, etc. The tool will then pass a boolean to an API exposed by the package as shown below.

// Begin by initializing the class
final Analytics analytics = Analytics(...);

// The boolean below simulates the user deciding to opt-out
// of Analytics collection
final bool status = false;

// Call the method to pass the boolean
analytics.setTelemetry(status);

Displaying Consent Message to Users

When a user first uses any tool with this package enabled, they will be enrolled into Analytics collection. It will be the responsiblity of the tool using this package to display the proper Analytics messaging and inform them on how to Opt-Out of Analytics collection if they wish. The package will expose APIs that will make it easy to configure Opt-In status.

For this use case, it is best to use the Analytics static method getConsentMessage which requires passing in the DashTool currently using this package.

Passing in the DashTool is necessary so that the message can include which tool is seeking consent.

final String consentMessage = Analytics.getConsentMessage(
  tool: DashTool.flutterTools
);

/// Printing out the consent message above returns the below
///
/// The flutter tools uses Google Analytics to report usage and diagnostic data
/// along with package dependencies, and crash reporting to send basic crash reports.
/// This data is used to help improve the Dart platform, Flutter framework, and related tools.
/// 
/// Telemetry is not sent on the very first run.
/// To disable reporting of telemetry, run this terminal command:
/// 
/// [dart|flutter] --disable-telemetry.
/// If you opt out of telemetry, an opt-out event will be sent,
/// and then no further information will be sent.
/// This data is collected in accordance with the
/// Google Privacy Policy (https://policies.google.com/privacy).

Checking User Opt-In Status

Some tools may need to know if the user has opted in for Analytics collection in order to enable additional functionality. The example below shows how to check the status.

// Begin by initializing the class
final Analytics analytics = Analytics(...);

// This getter will return a boolean showing the status;
// print statement used for trivial usage example
print('This user's status: ${analytics.telemetryEnabled}');  // true if opted-in

Checking for New Versions of Consent Message

In the event that the package consent messaging needs has been updated, an API has been exposed on an instance of Analytics that will notify the tool using this package whether to display the message again.

// Begin by initializing the class
//
// This is assuming that the tool has already been onboarded
// and that the user has already seen the previous version of
// the consent message
final Analytics analytics = Analytics(...);


// Much like the first example, if there is a new version of
// the tools message that needs to be shown, use the same work
// workflow
if (analytics.shouldShowMessage) {
  
  // Simulates displaying the message, this will vary from
  // client to client; ie. stdout, popup in IDE, etc.
  print(analytics.getConsentMessage);

  // After receiving confirmation that the message has been
  // displayed, invoking the below method will successfully
  // onboard the tool into the config file and allow for
  // events to be sent on the next creation of the analytics
  // instance
  //
  // The rest of the example below assumes that the tool has
  // already been onboarded in a previous run
  analytics.clientShowedMessage();
}

It is important to note events will not be sent if there is a new version of the consent message.

Developing Within package:unified_analytics

When contributing to this package, if the developer needs to verify that events have been sent, the developer should the use development constructor so that the events being sent are not going into the production instance.

final Analytics analytics = Analytics.development(...);

Reach out to maintainers to get access to the test Google Analytics endpoint.

Advanced Usage: Querying Locally Persisted Logs

This package enables tools to persist the events that have been sent to Google Analytics for logging by default. This can be very helpful if tools would like to understand the user's activity level across all related tooling. For example, if querying the locally persisted logs shows that the user has not been active for N number of days, a tool that works within an IDE can prompt the user with a survey to understand why their level of activity has dropped.

The snippet below shows how to invoke the query and a sample response.

// Begin by initializing the class
final Analytics analytics = Analytics(...);

// Printing the query results returns json formatted
// string to view; data can also be accessed through
// [LogFileStats] getters
print(analytics.logFileStats());

// Prints out the below
// {
//     "startDateTime": "2023-02-22 15:23:24.410921",
//     "minsFromStartDateTime": 20319,
//     "endDateTime": "2023-03-08 15:46:36.318211",
//     "minsFromEndDateTime": 136,
//     "sessionCount": 7,
//     "flutterChannelCount": 2,
//     "toolCount": 1,
//     "recordCount": 23,
//     "eventCount": {
//         "hot_reload_time": 16,
//         "analytics_collection_enabled": 7,
//         ... scales up with number of events
//     }
// }

Explanation of the each key above

  • startDateTime: the earliest event that was sent
  • minsFromStartDateTime: the number of minutes elapsed since the earliest message
  • endDateTime: the latest, most recent event that was sent
  • minsFromEndDateTime: the number of minutes elapsed since the latest message
  • sessionCount: count of sessions; sessions have a minimum time of 30 minutes
  • flutterChannelCount: count of flutter channels (can be 0 if developer is a Dart dev only)
  • toolCount: count of the Dart and Flutter tools sending analytics
  • recordCount: count of the total number of events in the log file
  • eventCount: counts each unique event and how many times they occurred in the log file