1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/services/sync/modules/healthreport.jsm Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,180 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +"use strict"; 1.9 + 1.10 +this.EXPORTED_SYMBOLS = [ 1.11 + "SyncProvider", 1.12 +]; 1.13 + 1.14 +const {classes: Cc, interfaces: Ci, utils: Cu} = Components; 1.15 + 1.16 +Cu.import("resource://gre/modules/Metrics.jsm", this); 1.17 +Cu.import("resource://gre/modules/Promise.jsm", this); 1.18 +Cu.import("resource://gre/modules/Services.jsm", this); 1.19 +Cu.import("resource://gre/modules/XPCOMUtils.jsm", this); 1.20 + 1.21 +const DAILY_LAST_NUMERIC_FIELD = {type: Metrics.Storage.FIELD_DAILY_LAST_NUMERIC}; 1.22 +const DAILY_LAST_TEXT_FIELD = {type: Metrics.Storage.FIELD_DAILY_LAST_TEXT}; 1.23 +const DAILY_COUNTER_FIELD = {type: Metrics.Storage.FIELD_DAILY_COUNTER}; 1.24 + 1.25 +XPCOMUtils.defineLazyModuleGetter(this, "Weave", 1.26 + "resource://services-sync/main.js"); 1.27 + 1.28 +function SyncMeasurement1() { 1.29 + Metrics.Measurement.call(this); 1.30 +} 1.31 + 1.32 +SyncMeasurement1.prototype = Object.freeze({ 1.33 + __proto__: Metrics.Measurement.prototype, 1.34 + 1.35 + name: "sync", 1.36 + version: 1, 1.37 + 1.38 + fields: { 1.39 + enabled: DAILY_LAST_NUMERIC_FIELD, 1.40 + preferredProtocol: DAILY_LAST_TEXT_FIELD, 1.41 + activeProtocol: DAILY_LAST_TEXT_FIELD, 1.42 + syncStart: DAILY_COUNTER_FIELD, 1.43 + syncSuccess: DAILY_COUNTER_FIELD, 1.44 + syncError: DAILY_COUNTER_FIELD, 1.45 + }, 1.46 +}); 1.47 + 1.48 +function SyncDevicesMeasurement1() { 1.49 + Metrics.Measurement.call(this); 1.50 +} 1.51 + 1.52 +SyncDevicesMeasurement1.prototype = Object.freeze({ 1.53 + __proto__: Metrics.Measurement.prototype, 1.54 + 1.55 + name: "devices", 1.56 + version: 1, 1.57 + 1.58 + fields: {}, 1.59 + 1.60 + shouldIncludeField: function (name) { 1.61 + return true; 1.62 + }, 1.63 + 1.64 + fieldType: function (name) { 1.65 + return Metrics.Storage.FIELD_DAILY_COUNTER; 1.66 + }, 1.67 +}); 1.68 + 1.69 +this.SyncProvider = function () { 1.70 + Metrics.Provider.call(this); 1.71 +}; 1.72 +SyncProvider.prototype = Object.freeze({ 1.73 + __proto__: Metrics.Provider.prototype, 1.74 + 1.75 + name: "org.mozilla.sync", 1.76 + 1.77 + measurementTypes: [ 1.78 + SyncDevicesMeasurement1, 1.79 + SyncMeasurement1, 1.80 + ], 1.81 + 1.82 + _OBSERVERS: [ 1.83 + "weave:service:sync:start", 1.84 + "weave:service:sync:finish", 1.85 + "weave:service:sync:error", 1.86 + ], 1.87 + 1.88 + postInit: function () { 1.89 + for (let o of this._OBSERVERS) { 1.90 + Services.obs.addObserver(this, o, false); 1.91 + } 1.92 + 1.93 + return Promise.resolve(); 1.94 + }, 1.95 + 1.96 + onShutdown: function () { 1.97 + for (let o of this._OBSERVERS) { 1.98 + Services.obs.removeObserver(this, o); 1.99 + } 1.100 + 1.101 + return Promise.resolve(); 1.102 + }, 1.103 + 1.104 + observe: function (subject, topic, data) { 1.105 + let field; 1.106 + switch (topic) { 1.107 + case "weave:service:sync:start": 1.108 + field = "syncStart"; 1.109 + break; 1.110 + 1.111 + case "weave:service:sync:finish": 1.112 + field = "syncSuccess"; 1.113 + break; 1.114 + 1.115 + case "weave:service:sync:error": 1.116 + field = "syncError"; 1.117 + break; 1.118 + } 1.119 + 1.120 + let m = this.getMeasurement(SyncMeasurement1.prototype.name, 1.121 + SyncMeasurement1.prototype.version); 1.122 + return this.enqueueStorageOperation(function recordSyncEvent() { 1.123 + return m.incrementDailyCounter(field); 1.124 + }); 1.125 + }, 1.126 + 1.127 + collectDailyData: function () { 1.128 + return this.storage.enqueueTransaction(this._populateDailyData.bind(this)); 1.129 + }, 1.130 + 1.131 + _populateDailyData: function* () { 1.132 + let m = this.getMeasurement(SyncMeasurement1.prototype.name, 1.133 + SyncMeasurement1.prototype.version); 1.134 + 1.135 + let svc = Cc["@mozilla.org/weave/service;1"] 1.136 + .getService(Ci.nsISupports) 1.137 + .wrappedJSObject; 1.138 + 1.139 + let enabled = svc.enabled; 1.140 + yield m.setDailyLastNumeric("enabled", enabled ? 1 : 0); 1.141 + 1.142 + // preferredProtocol is constant and only changes as the client 1.143 + // evolves. 1.144 + yield m.setDailyLastText("preferredProtocol", "1.5"); 1.145 + 1.146 + let protocol = svc.fxAccountsEnabled ? "1.5" : "1.1"; 1.147 + yield m.setDailyLastText("activeProtocol", protocol); 1.148 + 1.149 + if (!enabled) { 1.150 + return; 1.151 + } 1.152 + 1.153 + // Before grabbing more information, be sure the Sync service 1.154 + // is fully initialized. This has the potential to initialize 1.155 + // Sync on the spot. This may be undesired if Sync appears to 1.156 + // be enabled but it really isn't. That responsibility should 1.157 + // be up to svc.enabled to not return false positives, however. 1.158 + yield svc.whenLoaded(); 1.159 + 1.160 + if (Weave.Status.service != Weave.STATUS_OK) { 1.161 + return; 1.162 + } 1.163 + 1.164 + // Device types are dynamic. So we need to dynamically create fields if 1.165 + // they don't exist. 1.166 + let dm = this.getMeasurement(SyncDevicesMeasurement1.prototype.name, 1.167 + SyncDevicesMeasurement1.prototype.version); 1.168 + let devices = Weave.Service.clientsEngine.deviceTypes; 1.169 + for (let [field, count] of devices) { 1.170 + let hasField = this.storage.hasFieldFromMeasurement(dm.id, field, 1.171 + this.storage.FIELD_DAILY_LAST_NUMERIC); 1.172 + let fieldID; 1.173 + if (hasField) { 1.174 + fieldID = this.storage.fieldIDFromMeasurement(dm.id, field); 1.175 + } else { 1.176 + fieldID = yield this.storage.registerField(dm.id, field, 1.177 + this.storage.FIELD_DAILY_LAST_NUMERIC); 1.178 + } 1.179 + 1.180 + yield this.storage.setDailyLastNumericFromFieldID(fieldID, count); 1.181 + } 1.182 + }, 1.183 +});