Bug 1308337 - Part 4: Instrument FetchMetaGlobal stage r=nalexander
MozReview-Commit-ID: 6zXqgsAIajN
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/GlobalSession.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/GlobalSession.java
@@ -290,16 +290,20 @@ public class GlobalSession implements Ht
this.abort(e, "No such stage " + next);
return;
}
this.currentState = next;
Logger.info(LOG_TAG, "Running next stage " + next + " (" + nextStage + ")...");
// For named stages, use the repository name.
String collectorName = currentState.getRepositoryName();
+ // For unnamed, non-repository stages use name of the stage itself.
+ if (collectorName == null) {
+ collectorName = currentState.name();
+ }
final TelemetryStageCollector stageCollector = telemetryCollector.collectorFor(collectorName);
// Stage is responsible for setting the 'finished' timestamp when appropriate.
stageCollector.started = SystemClock.elapsedRealtime();
try {
nextStage.execute(this, stageCollector);
} catch (Exception ex) {
Logger.warn(LOG_TAG, "Caught exception " + ex + " running stage " + next);
@@ -654,22 +658,23 @@ public class GlobalSession implements Ht
}
request.put(keysRecord);
}
/*
* meta/global callbacks.
*/
- public void processMetaGlobal(MetaGlobal global) {
+ public void processMetaGlobal(MetaGlobal global, TelemetryStageCollector stageCollector) {
config.metaGlobal = global;
Long storageVersion = global.getStorageVersion();
if (storageVersion == null) {
Logger.warn(LOG_TAG, "Malformed remote meta/global: could not retrieve remote storage version.");
+ stageCollector.error = new TelemetryCollector.StageErrorBuilder("metaglobal", "noversion").build();
freshStart();
return;
}
if (storageVersion < STORAGE_VERSION) {
Logger.warn(LOG_TAG, "Outdated server: reported " +
"remote storage version " + storageVersion + " < " +
"local storage version " + STORAGE_VERSION);
freshStart();
@@ -680,16 +685,17 @@ public class GlobalSession implements Ht
"remote storage version " + storageVersion + " > " +
"local storage version " + STORAGE_VERSION);
requiresUpgrade();
return;
}
String remoteSyncID = global.getSyncID();
if (remoteSyncID == null) {
Logger.warn(LOG_TAG, "Malformed remote meta/global: could not retrieve remote syncID.");
+ stageCollector.error = new TelemetryCollector.StageErrorBuilder("metaglobal", "nosyncid").build();
freshStart();
return;
}
String localSyncID = config.syncID;
if (!remoteSyncID.equals(localSyncID)) {
Logger.warn(LOG_TAG, "Remote syncID different from local syncID: resetting client and assuming remote syncID.");
resetAllStages();
config.purgeCryptoKeys();
@@ -1126,17 +1132,17 @@ public class GlobalSession implements Ht
/**
* Suggest that your Sync client needs to be upgraded to work
* with this server.
*/
public void requiresUpgrade() {
Logger.info(LOG_TAG, "Client outdated storage version; requires update.");
// TODO: notify UI.
- this.abort(null, "Requires upgrade");
+ this.abort(null, "Requires upgrade from " + STORAGE_VERSION);
}
/**
* If meta/global is missing or malformed, throws a MetaGlobalException.
* Otherwise, returns true if there is an entry for this engine in the
* meta/global "engines" object.
* <p>
* This is a global/permanent setting, not a local/temporary setting. For the
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/FetchMetaGlobalStage.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/FetchMetaGlobalStage.java
@@ -1,76 +1,102 @@
/* 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/. */
package org.mozilla.gecko.sync.stage;
+import android.os.SystemClock;
+
import org.mozilla.gecko.background.common.log.Logger;
import org.mozilla.gecko.sync.GlobalSession;
+import org.mozilla.gecko.sync.HTTPFailureException;
import org.mozilla.gecko.sync.InfoCollections;
import org.mozilla.gecko.sync.MetaGlobal;
import org.mozilla.gecko.sync.PersistedMetaGlobal;
import org.mozilla.gecko.sync.delegates.MetaGlobalDelegate;
import org.mozilla.gecko.sync.net.SyncStorageResponse;
+import org.mozilla.gecko.sync.telemetry.TelemetryCollector;
public class FetchMetaGlobalStage extends AbstractNonRepositorySyncStage {
private static final String LOG_TAG = "FetchMetaGlobalStage";
private static final String META_COLLECTION = "meta";
+ private static final String TELEMETRY_ERROR_NAME = "metaglobal";
+ private static final String TELEMETRY_ERROR_MISSING = "missing";
+ private static final String TELEMETRY_ERROR_NO_INFO_COLLECTIONS = "noic";
+
public class StageMetaGlobalDelegate implements MetaGlobalDelegate {
private final GlobalSession session;
public StageMetaGlobalDelegate(GlobalSession session) {
this.session = session;
}
@Override
public void handleSuccess(MetaGlobal global, SyncStorageResponse response) {
Logger.trace(LOG_TAG, "Persisting fetched meta/global and last modified.");
PersistedMetaGlobal pmg = session.config.persistedMetaGlobal();
pmg.persistMetaGlobal(global);
// Take the timestamp from the response since it is later than the timestamp from info/collections.
pmg.persistLastModified(response.normalizedWeaveTimestamp());
- session.processMetaGlobal(global);
+ telemetryStageCollector.finished = SystemClock.elapsedRealtime();
+ session.processMetaGlobal(global, telemetryStageCollector);
}
@Override
public void handleFailure(SyncStorageResponse response) {
+ telemetryStageCollector.error = new TelemetryCollector.StageErrorBuilder()
+ .setLastException(new HTTPFailureException(response))
+ .build();
+ telemetryStageCollector.finished = SystemClock.elapsedRealtime();
session.handleHTTPError(response, "Failure fetching meta/global.");
}
@Override
public void handleError(Exception e) {
+ telemetryStageCollector.error = new TelemetryCollector.StageErrorBuilder()
+ .setLastException(e)
+ .build();
+ telemetryStageCollector.finished = SystemClock.elapsedRealtime();
session.abort(e, "Failure fetching meta/global.");
}
@Override
public void handleMissing(MetaGlobal global, SyncStorageResponse response) {
+ // While not strictly an error, it's good to keep track of this.
+ telemetryStageCollector.error = new TelemetryCollector
+ .StageErrorBuilder(TELEMETRY_ERROR_NAME, TELEMETRY_ERROR_MISSING)
+ .build();
session.processMissingMetaGlobal(global);
}
}
@Override
public void execute() throws NoSuchStageException {
InfoCollections infoCollections = session.config.infoCollections;
if (infoCollections == null) {
+ telemetryStageCollector.finished = SystemClock.elapsedRealtime();
+ telemetryStageCollector.error = new TelemetryCollector
+ .StageErrorBuilder(TELEMETRY_ERROR_NAME, TELEMETRY_ERROR_NO_INFO_COLLECTIONS)
+ .build();
session.abort(null, "No info/collections set in FetchMetaGlobalStage.");
return;
}
final long lastModified = session.config.persistedMetaGlobal().lastModified();
if (!infoCollections.updateNeeded(META_COLLECTION, lastModified)) {
// Try to use our local collection keys for this session.
Logger.info(LOG_TAG, "Trying to use persisted meta/global for this session.");
MetaGlobal global = session.config.persistedMetaGlobal().metaGlobal(session.config.metaURL(), session.getAuthHeaderProvider());
if (global != null) {
Logger.info(LOG_TAG, "Using persisted meta/global for this session.");
- session.processMetaGlobal(global); // Calls session.advance().
+ telemetryStageCollector.finished = SystemClock.elapsedRealtime();
+ session.processMetaGlobal(global, telemetryStageCollector); // Calls session.advance().
return;
}
Logger.info(LOG_TAG, "Failed to use persisted meta/global for this session.");
}
// We need an update: fetch or upload meta/global as necessary.
// We assert when we believe meta/global was last modified via X-I-U-S.
Logger.info(LOG_TAG, "Fetching fresh meta/global for this session.");
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/GlobalSyncStage.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/GlobalSyncStage.java
@@ -1,14 +1,16 @@
/* 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/. */
package org.mozilla.gecko.sync.stage;
+import android.support.annotation.Nullable;
+
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import org.mozilla.gecko.sync.GlobalSession;
import org.mozilla.gecko.sync.telemetry.TelemetryStageCollector;
@@ -63,17 +65,17 @@ public interface GlobalSyncStage {
* @return an immutable collection of Stages.
*/
public static Collection<Stage> getNamedStages() {
return Collections.unmodifiableCollection(named.values());
}
// Each Stage tracks its repositoryName.
private final String repositoryName;
- public String getRepositoryName() {
+ @Nullable public String getRepositoryName() {
return repositoryName;
}
private Stage() {
this.repositoryName = null;
}
private Stage(final String name) {