diff --git a/.eslintignore b/.eslintignore index b126955..4ced8a0 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,2 +1,3 @@ testpilot-metrics.js lib/shield/*.js +lib/testpilot/*.js diff --git a/lib/testpilot/experiment.js b/lib/testpilot/experiment.js new file mode 100644 index 0000000..329bd69 --- /dev/null +++ b/lib/testpilot/experiment.js @@ -0,0 +1,102 @@ +const { AddonManager } = require('resource://gre/modules/AddonManager.jsm'); +const { ClientID } = require('resource://gre/modules/ClientID.jsm'); +const Events = require('sdk/system/events'); +const { Services } = require('resource://gre/modules/Services.jsm'); +const { storage } = require('sdk/simple-storage'); +const { + TelemetryController +} = require('resource://gre/modules/TelemetryController.jsm'); +const { Request } = require('sdk/request'); + + +const EVENT_SEND_METRIC = 'testpilot::send-metric'; +const startTime = (Services.startup.getStartupInfo().process); + +function makeTimestamp(timestamp) { + return Math.round((timestamp - startTime) / 1000); +} + +function experimentPing(event) { + const timestamp = new Date(); + const { subject, data } = event; + let parsed; + try { + parsed = JSON.parse(data); + } catch (err) { + // eslint-disable-next-line no-console + return console.error(`Dropping bad metrics packet: ${err}`); + } + + AddonManager.getAddonByID(subject, addon => { + const payload = { + test: subject, + version: addon.version, + timestamp: makeTimestamp(timestamp), + variants: storage.experimentVariants && + subject in storage.experimentVariants + ? storage.experimentVariants[subject] + : null, + payload: parsed + }; + TelemetryController.submitExternalPing('testpilottest', payload, { + addClientId: true, + addEnvironment: true + }); + + // TODO: DRY up this ping centre code here and in lib/Telemetry. + const pcPing = TelemetryController.getCurrentPingData(); + pcPing.type = 'testpilot'; + pcPing.payload = payload; + const pcPayload = { + // 'method' is used by testpilot-metrics library. + // 'event' was used before that library existed. + event_type: parsed.event || parsed.method, + client_time: makeTimestamp(parsed.timestamp || timestamp), + addon_id: subject, + addon_version: addon.version, + firefox_version: pcPing.environment.build.version, + os_name: pcPing.environment.system.os.name, + os_version: pcPing.environment.system.os.version, + locale: pcPing.environment.settings.locale, + // Note: these two keys are normally inserted by the ping-centre client. + client_id: ClientID.getCachedClientID(), + topic: 'testpilot' + }; + // Add any other extra top-level keys = require(the payload, possibly including + // 'object' or 'category', among others. + Object.keys(parsed).forEach(f => { + // Ignore the keys we've already added to `pcPayload`. + const ignored = ['event', 'method', 'timestamp']; + if (!ignored.includes(f)) { + pcPayload[f] = parsed[f]; + } + }); + + const req = new Request({ + url: 'https://tiles.services.mozilla.com/v3/links/ping-centre', + contentType: 'application/json', + content: JSON.stringify(pcPayload) + }); + req.post(); + }); +} + +function Experiment() { + Events.on(EVENT_SEND_METRIC, experimentPing); +} + +Experiment.prototype = { + constructor: function() { + Events.on(EVENT_SEND_METRIC, experimentPing); + }, + + ping: function(event) { + experimentPing(event); + }, + + teardown: function() { + Events.off(EVENT_SEND_METRIC, experimentPing); + } +}; + +module.exports = Experiment; diff --git a/testpilot-metrics.js b/testpilot-metrics.js index f68aae3..2aad4bd 100644 --- a/testpilot-metrics.js +++ b/testpilot-metrics.js @@ -1,6 +1,9 @@ // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +const Experiment = require('./lib/testpilot/experiment'); + +const experiment = new Experiment(); /** * Class that represents a metrics event broker. Events are sent to Google @@ -170,6 +173,7 @@ Metrics.prototype = { }; try { + console.log("notifying observerser of testpilot::send-metric; subject: ", subject, " stringified: ", stringified); Services.obs.notifyObservers(subject, 'testpilot::send-metric', stringified); this._log(`Sent client message via nsIObserverService: ${stringified}`); } catch (ex) {