Bug 659196 - Improve telemetry metadata, introduce simple counters r=Mossop
authorTaras Glek <tglek@mozilla.com>
Wed, 01 Jun 2011 02:23:34 +0200
changeset 70470 998d4edbf4b323e1766a292ec29ff4cf78b9fe52
parent 70469 fabceeb16a3de2c8fda1872084f2dc92671f2ed0
child 70471 a5a1a64c111215633a289dafd78e055beaccfce7
push id20332
push usertglek@mozilla.com
push dateThu, 02 Jun 2011 20:05:53 +0000
treeherdermozilla-central@998d4edbf4b3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersMossop
bugs659196
milestone7.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 659196 - Improve telemetry metadata, introduce simple counters r=Mossop
toolkit/components/telemetry/TelemetryPing.js
toolkit/components/telemetry/tests/unit/test_TelemetryPing.js
--- a/toolkit/components/telemetry/TelemetryPing.js
+++ b/toolkit/components/telemetry/TelemetryPing.js
@@ -38,16 +38,19 @@
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
+// When modifying the payload in incompatible ways, please bump this version number
+const PAYLOAD_VERSION = 1;
+
 const PREF_SERVER = "toolkit.telemetry.server";
 const PREF_ENABLED = "toolkit.telemetry.enabled";
 // Do not gather data more than once a minute
 const TELEMETRY_INTERVAL = 60;
 // Delay before intializing telemetry (ms)
 const TELEMETRY_DELAY = 60000;
 // about:memory values to turn into histograms
 const MEM_HISTOGRAMS = {
@@ -107,32 +110,74 @@ function getHistograms() {
 }
 
 function generateUUID() {
   return Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator)
          .generateUUID().toString();
 }
 
 /**
- * @return request metadata
+ * Gets metadata about the platform the application is running on. This
+ * should remain consistent across multiple telemetry pings.
+ * 
+ * @param  reason
+ *         The reason for the telemetry ping, this will be included in the
+ *         returned metadata,
+ * @return The metadata as a JS object
  */
 function getMetadata(reason) {
-  let si = Cc["@mozilla.org/toolkit/app-startup;1"].
-           getService(Ci.nsIAppStartup).getStartupInfo();
   let ai = Services.appinfo;
   let ret = {
-    uptime: (new Date() - si.process),
     reason: reason,
     OS: ai.OS,
-    XPCOMABI: ai.XPCOMABI,
-    ID: ai.ID,
-    version: ai.version,
-    name: ai.name,
+    appID: ai.ID,
+    appVersion: ai.version,
+    appName: ai.name,
     appBuildID: ai.appBuildID,
     platformBuildID: ai.platformBuildID,
+  };
+
+  // sysinfo fields is not always available, get what we can.
+  let sysInfo = Cc["@mozilla.org/system-info;1"].getService(Ci.nsIPropertyBag2);
+  let fields = ["cpucount", "memsize", "arch", "version", "device", "manufacturer", "hardware"];
+  for each (let field in fields) {
+    let value;
+    try {
+      value = sysInfo.getProperty(field);
+    } catch (e) {
+      continue
+    }
+    if (field == "memsize") {
+      // Send RAM size in megabytes. Rounding because sysinfo doesn't
+      // always provide RAM in multiples of 1024.
+      value = Math.round(value / 1024 / 1024)
+    }
+    ret[field] = value
+  }
+  return ret;
+}
+
+/**
+ * Gets a series of simple measurements (counters). At the moment, this
+ * only returns startup data from nsIAppStartup.getStartupInfo().
+ * 
+ * @return simple measurements as a dictionary.
+ */
+function getSimpleMeasurements() {
+  let si = Cc["@mozilla.org/toolkit/app-startup;1"].
+           getService(Ci.nsIAppStartup).getStartupInfo();
+
+  var ret = {
+    // uptime in minutes
+    uptime: Math.round((new Date() - si.process) / 60000)
+  }
+  for each (let field in ["main", "firstPaint", "sessionRestored"]) {
+    if (!(field in si))
+      continue;
+    ret[field] = si[field] - si.process
   }
   return ret;
 }
 
 function TelemetryPing() {}
 
 TelemetryPing.prototype = {
   _histograms: {},
@@ -175,17 +220,19 @@ TelemetryPing.prototype = {
   /**
    * Send data to the server. Record success/send-time in histograms
    */
   send: function send(reason, server) {
     // populate histograms one last time
     this.gatherMemory();
     let nativeJSON = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON);
     let payload = {
+      ver: PAYLOAD_VERSION,
       info: getMetadata(reason),
+      simpleMeasurements: getSimpleMeasurements(),
       histograms: getHistograms()
     };
     let isTestPing = (reason == "test-ping");
     // Generate a unique id once per session so the server can cope with duplicate submissions.
     // Use a deterministic url for testing.
     if (!this._path)
       this._path = "/submit/telemetry/" + (isTestPing ? reason : generateUUID());
     
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryPing.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetryPing.js
@@ -50,34 +50,32 @@ function readBytesFromInputStream(inputS
 
 function checkHistograms(request, response) {
   // do not need the http server anymore
   httpserver.stop(do_test_finished);
   let s = request.bodyInputStream
   let payload = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON)
                                              .decode(readBytesFromInputStream(s))
 
-  do_check_true(payload.info.uptime >= 0)
+  do_check_true(payload.simpleMeasurements.uptime >= 0)
 
   // get rid of the non-deterministic field
-  payload.info.uptime = 0;
   const expected_info = {
-    uptime: 0,
     reason: "test-ping",
     OS: "XPCShell", 
-    XPCOMABI: "noarch-spidermonkey", 
-    ID: "xpcshell@tests.mozilla.org", 
-    version: "1", 
-    name: "XPCShell", 
+    appID: "xpcshell@tests.mozilla.org", 
+    appVersion: "1", 
+    appName: "XPCShell", 
     appBuildID: "2007010101",
     platformBuildID: "2007010101"
   };
 
-  do_check_eq(uneval(payload.info), 
-              uneval(expected_info));
+  for (let f in expected_info) {
+    do_check_eq(payload.info[f], expected_info[f]);
+  }
 
   const TELEMETRY_PING = "telemetry.ping (ms)";
   const TELEMETRY_SUCCESS = "telemetry.success (No, Yes)";
   do_check_true(TELEMETRY_PING in payload.histograms)
 
   // There should be one successful report from the previos telemetry ping
   const expected_tc = {
     range: [1, 2],